local skynet = require "skynet"
local CMD = require "center_proto"
local snax = require "snax"
local cluster = require "cluster"
local buffrw = require "buffrw"
local cjson = require "cjson"
local db = require "dblib"

local NameLen = 64
local TIMINGMATCH = {}

local matchser = nil
local MatchStage = 0 --1:预赛 2:半决赛 3:决赛
local MatchConf = nil --赛事配置
local UserTb = {}
local TableTb = {}
local UserNum = 0
local TableUserNum --每个桌子人数
local SixtySeconds = 60
local ThreeHundredSeconds = 300
local Msg = {[1] ="预赛阶段即将结束，等待其他玩家完成比赛", [2] = "初赛阶段即将结束，等待其他玩家完成比赛", [3] = "决赛阶段即将结束，等待颁奖"}
local QueryStr = {}
local MatchId = nil

local UserState = {
    RegisterSucceed       = 1, --注册成功
    RegisterOverWait      = 2, --进假桌子等待
    MatchOverWait         = 3, --该轮打完，等待其他桌子结束
    InMatchIng            = 4, --在桌子中打牌
    -- InMatchTwo            = 5 --第二轮比赛中
    -- InMatchThree          = 6 --第三轮比赛中
}


local TimingMatchState = {
    BeforeStartDate = 1,         --未到有效期
    Readymatch      = 2,         --接受报名
    FiveMinutes     = 3,         --五分钟通知
    OneMinutes      = 4,         --一分钟下发预进入
    Matching        = 5,         --比赛中
    Matchingend     = 6,         --比赛结束
    ZeroReset       = 7,         --零点重置
    AfterEndDate    = 8,         --过了有效期
}

local DbIntState = {
    Registed    = 1,         --报名
    Quit        = 2,         --退赛
    MissMatch   = 3,         --缺赛
    AttendMatch = 4,         --参赛
    GetAward    = 5,         --获奖
}


local TimingState = TimingMatchState.BeforeStartDate  --定时赛当前所处状态，对应 TimingMatchState子项
TIMINGMATCH.CreatTable =  false
TIMINGMATCH.GameAddr = nil

function QueryStr:AddStr(str)
    if type(str) == "number" and string.sub(self.str,string.len(self.str))=="(" then        
        self.str = self.str..str
    elseif type(str) == "number" then        
        self.str = self.str..","..str
    elseif type(str) == "string" and  string.sub(self.str,string.len(self.str))=="(" then 
        self.str = self.str.."\""..str.."\""
    elseif type(str) == "string" and  string.len(self.str)== 0 or string.sub(self.str,string.len(self.str))=="(" then 
        self.str = self.str..str
    elseif type(str) == "string" and  string.len(self.str) >0 then 
        if str == ")" then
            self.str = self.str..str
        else        
            self.str = self.str..",\""..str.."\""
        end
    end
end

function QueryStr:Clean()
    self.str = ""
end

function TIMINGMATCH.CreateUUID()

    local template ="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    d = io.open("/dev/urandom", "r"):read(4)
    math.randomseed(os.time() + d:byte(1) + (d:byte(2) * 256) + (d:byte(3) * 65536) + (d:byte(4) * 4294967296))
    return string.gsub(template, "x", function (c)
          local v = (c == "x") and math.random(0, 0xf) or math.random(8, 0xb)
          return string.format("%x", v)
          end)

end

function TIMINGMATCH.Shuffle(data)

    local temp = {}
    for k, v in pairs(data) do 
        table.insert(temp,v)
    end

    local tab = {}
    local index = 1
    math.randomseed(os.time())
    while #temp ~= 0 do
        local n = math.random(0, #temp)
        if temp[n] ~= nil then
            tab[index] = temp[n]
            table.remove(temp, n)
            index = index + 1
        end
    end
    return tab
end

function TIMINGMATCH.AddUserLog(IntUserid,IntState,IntMsgId,IsRboot,Rank)
    QueryStr:Clean()
    QueryStr:AddStr("call pr_MatchUserLog(")
    QueryStr:AddStr(IntUserid)
    QueryStr:AddStr(MatchConf["match_type"])
    QueryStr:AddStr(MatchConf["match_name"])
    QueryStr:AddStr(MatchConf["pay_type"])
    QueryStr:AddStr(MatchConf["pay_num"])
    QueryStr:AddStr(IntState)
	 QueryStr:AddStr(IntMsgId)
    --QueryStr:AddStr(IntAwardType)
    --QueryStr:AddStr(IntAwardNum)
    QueryStr:AddStr(MatchId)
    QueryStr:AddStr(IsRboot)
    QueryStr:AddStr(Rank)
    QueryStr:AddStr(")")
    -- local sqlstr = "call pr_MatchUserLog("..userid..","..MatchConf["match_type"]..",\""..MatchConf["match_name"].."\","..MatchConf["pay_type"]..","..MatchConf["pay_num"]..","..state..",0,0);";
    --skynet.error("[timingmatch] TIMINGMATCH.AddUserLog  QueryStr ",QueryStr.str)
    db.call(QueryStr.str)
end

function TIMINGMATCH.AddMatchLog()

   
    QueryStr:Clean()
    QueryStr:AddStr("call pr_MatchMatchLog(")
    QueryStr:AddStr(MatchId)
    QueryStr:AddStr(MatchConf["match_type"])
    QueryStr:AddStr(MatchConf["match_name"])
    QueryStr:AddStr(MatchConf["pay_type"])
    QueryStr:AddStr(MatchConf["pay_num"])
    QueryStr:AddStr(TableUserNum)
    QueryStr:AddStr(MatchConf["game_type"])
    QueryStr:AddStr(0)
    QueryStr:AddStr(TIMINGMATCH.TableId)
    QueryStr:AddStr(TIMINGMATCH.StartMatch)
    QueryStr:AddStr(TIMINGMATCH.EndMatch)
    QueryStr:AddStr(")")
    skynet.error("[timingmatch] AddMatchLog",QueryStr.str)
    db.call(QueryStr.str)
end

function TIMINGMATCH.FormotGameNickName(nickname,length)
  
    if nickname==nil then
        return ""
    end
    local lengthUTF_8 = #(string.gsub(nickname, "[\128-\191]", ""))
    if lengthUTF_8 <= length then
        return nickname
    else
        local matchStr = "^"
        for var=1, length do
            matchStr = matchStr..".[\128-\191]*"
        end
        local str = string.match(nickname, matchStr)
        return string.format("%s...",str);
    end
end

function TIMINGMATCH.SetTimingMatchState(sta)
    TimingState = sta
    skynet.error("[timingmatch] TIMINGMATCH.SetTimingMatchState  TimingState = ",sta)
end

--从用户表里面获取用户  userid  用户ID
function TIMINGMATCH.GetUserForUserTb(userid)
    for k, v in pairs(UserTb) do 
        if v.UserId == userid then 
            return k
        end
    end
    return nil
end

function TIMINGMATCH.SetUserState(userid, state)

    local index = TIMINGMATCH.GetUserForUserTb(userid)
    if UserTb[index] then 
        UserTb[index].State = state
    end
end

--通知游戏服务器创建比赛所需的桌子
function TIMINGMATCH.ToGameCreatTable()
    
    skynet.error("[timingmatch]  TIMINGMATCH.ToGameCreatTable  UserNum = ",UserNum)
	TIMINGMATCH.CreatTable = false --创建桌子还未成功
    if UserNum < 1 then  --最少要一个玩家报名
        skynet.error("[timingmatch] ToGameCreatTable player_num too shao")
        --local BuffWr = buffrw.BuffWrite:new() 
        --BuffWr:clean()
        --BuffWr:proto(CMD.Main_match_module,CMD.Sub_NotifyMatchOver)
        --BuffWr:int4(skynet.self())
        --matchser.post.create_table(MatchConf["game_type"],BuffWr.buff)
        skynet.error("[timingmatch]  TIMINGMATCH.ToGameCreatTable UserNum < 1  CMD.MatchState_Match_end   send MatchState ",CMD.MatchState_Match_end)
        matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_Match_end,0)
		TIMINGMATCH.SetTimingMatchState(TimingMatchState.Matchingend)
        TIMINGMATCH.ResetData()
        return
    end
    local BuffWrite = buffrw.BuffWrite:new()  
    BuffWrite:proto(CMD.Main_match_module,CMD.Sub_CreateMatchTable)
    BuffWrite:int4(skynet.self())
    MatchConf["room_config"].jushu = MatchConf["match_config"]["graden"][MatchStage]["jushu"]  --把局数传给游戏服
    MatchConf["room_config"].difen = MatchConf["match_config"]["graden"][MatchStage]["difen"]
	local roomconf = cjson.encode(MatchConf["room_config"])
    BuffWrite:int2(string.len(roomconf))
    BuffWrite:str(tostring(roomconf),string.len(roomconf))

    
    
    --local tableNum = math.floor(tempUserNum/TableUserNum)

    
    if MatchStage == CMD.Match_ChuSai then  
		local TempUserTb = TIMINGMATCH.Shuffle(UserTb)
		--local tableNum = math.ceil(tempUserNum/TableUserNum)
        local tempUserNum = UserNum
        if UserNum < MatchConf["min_man"] then   -- 是否大于人数下线
            tempUserNum = MatchConf["min_man"]
        elseif UserNum > MatchConf["min_man"] then   -- 是否大于人数下线
            if UserNum % TableUserNum == 0 then
                tempUserNum = UserNum
            else
                tempUserNum = UserNum + (TableUserNum - (UserNum % TableUserNum))
            end
        end
    
		local tableNum = tempUserNum/TableUserNum
        skynet.error("[timingmatch]  TIMINGMATCH.ToGameCreatTable  Match_ChuSai tempUserNum UserNum  tableNum ",tempUserNum,UserNum,tableNum)
		BuffWrite:int4(tableNum) --桌子数
		BuffWrite:int4(UserNum) --人数
        for i = 1 , UserNum do   --   ????
            skynet.error("[timingmatch] ToGameCreatTable ",MatchStage,TempUserTb[i].UserId,TempUserTb[i].Score)
            BuffWrite:int4(TempUserTb[i].UserId)
            BuffWrite:int4(TempUserTb[i].IsRboot)
            --BuffWrite:str(TempUserTb[i].NikeName, NameLen)
            BuffWrite:int4(TempUserTb[i].Score)
        end
        
   elseif MatchStage == CMD.Match_YuSai or MatchStage == CMD.Match_JueSai then  
		--local tableNum = math.ceil(UserNum/TableUserNum)
		local tableNum = UserNum/TableUserNum
        skynet.error("[timingmatch]  TIMINGMATCH.ToGameCreatTable MatchStage == CMD.Match_YuSai or MatchStage == CMD.Match_JueSai tableNum    ",tableNum)
		BuffWrite:int4(tableNum) --桌子数
		BuffWrite:int4(UserNum) --人数
        for i = 1 , UserNum/2 do 
            skynet.error("[timingmatch] ToGameCreatTable ",MatchStage,UserTb[i].UserId,UserTb[i].Score,UserTb[UserNum-i+1].UserId,UserTb[UserNum-i+1].Score)
            BuffWrite:int4(UserTb[i].UserId)
            BuffWrite:int4(UserTb[i].IsRboot)
            --BuffWrite:str(UserTb[i].NikeName, NameLen)
            BuffWrite:int4(UserTb[i].Score)
             
            BuffWrite:int4(UserTb[UserNum-i+1].UserId)
            BuffWrite:int4(UserTb[UserNum-i+1].IsRboot)
            --BuffWrite:str(UserTb[UserNum-i+1].NikeName, NameLen)
            BuffWrite:int4(UserTb[UserNum-i+1].Score)
        end      
            --扩展信息      create_table
    end 
--skynet.error("[timingmatch] ToGameCreatTable log tempUserNum,TableUserNum,tableNum   ",tempUserNum,TableUserNum,tableNum)
    	
    
    matchser.post.create_table(MatchConf["game_type"],TIMINGMATCH.GameAddr,BuffWrite.buff)
	skynet.timeout(500,function() TIMINGMATCH.CheckCreatTable() end)
end

function TIMINGMATCH.CheckCreatTable()
    
    if TIMINGMATCH.CreatTable then 
        skynet.error("[timingmatch] MatchStage create table succ  ",MatchStage)
    else
        skynet.error("[timingmatch] MatchStage create table fail  ",MatchStage)
        for k, v in pairs(UserTb) do
        
            TIMINGMATCH.ReturnUserDiomand(v.UserId) --已报名的退钱 CMD.Sub_ModuleToMatch_NotifyMatchPause
            matchser.post.m_send_to_client(v.UserId, CMD.Main_match_module, CMD.Sub_ModuleToMatch_NotifyMatchPause,string.pack("I1",1))        
            skynet.error("[timingmatch] 游戏服务器创建桌子失败 userid: ",v.UserId,"赛赛id: ",MatchConf["match_name"],"游戏名称: ",MatchConf["game_type"] )
            matchser.post.recv_user_addr(v.UserId,MatchConf["match_number"],skynet.self(),0)
            matchser.post.m_send_to_center(v.UserId, 0)
        end
        matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_RunServer,0)
    end

end


--报名成功修改用户钻石
function TIMINGMATCH.DeductUserDiomand(UserId)

 local sqlstr = "call pr_MatchChagre("..UserId..","..MatchConf["pay_type"]..","..-MatchConf["pay_num"]..",@ReturnVal);"
    local res_sql = "select @ReturnVal;"
    local res1, res2 = db.call(sqlstr, res_sql)
    
    if res2[1]['@ReturnVal'] == 1 then 
        return true
    else
        return false    --  TODO  暂时都返回成功
    end
end

--取消报名修改用户钻石
function TIMINGMATCH.ReturnUserDiomand(UserId)

    local sqlstr = "call pr_MatchChagre("..UserId..","..MatchConf["pay_type"]..","..MatchConf["pay_num"]..",@ReturnVal);"
    local res_sql = "select @ReturnVal;"
    local res1, res2 = db.call(sqlstr, res_sql)
    
    if res2[1]['@ReturnVal'] == 1 then 
        skynet.error("[timingmatch] TIMINGMATCH.ReturnUserDiomand true")
        return true
    else
        skynet.error("[timingmatch] TIMINGMATCH.ReturnUserDiomand false")
        return false
    end

end

function TIMINGMATCH.Readymatch()
    local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime() 
    if  (timeNow > MatchConf["start_date"] ) and (timeNow < MatchConf["end_date"] ) then
        skynet.error("[timingmatch] TIMINGMATCH.Readymatch  timeNow >= start_date ")
		--if timeNow < MatchConf["start_time"] then
		--	TIMINGMATCH.SetTimingMatchState(TimingMatchState.Matching)
		--else
			skynet.error("[timingmatch] TIMINGMATCH.Readymatch  CMD.MatchState_ReadyMatch  ")
			matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_ReadyMatch,UserNum)
			TIMINGMATCH.SetTimingMatchState(TimingMatchState.Readymatch)
			if timeInterval < 0 then
				skynet.error("[timingmatch] TIMINGMATCH.Readymatch  timeInterval < 0   CMD.MatchState_Match_end  ")
				matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_Match_end,UserNum)
				TIMINGMATCH.SetTimingMatchState(TimingMatchState.Matchingend)
			end
			--TIMINGMATCH.SetTimingMatchState(TimingMatchState.Readymatch)
		--end
        return
    end
end

--距离开赛5分钟发广播
function TIMINGMATCH.BroadCastLeft5MinutesToAll() 
    local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime()
    
    if  (timeInterval <= ThreeHundredSeconds) then
        skynet.error("[timingmatch] TIMINGMATCH.BroadCastLeft5MinutesToAll  timeInterval <= ThreeHundredSeconds ")
		skynet.error("[timingmatch]  TIMINGMATCH.BroadCastLeft5MinutesToAll   timeNow,timeBase,start_time  timeInterval   ",timeNow,timeBase,MatchConf["start_time"],timeInterval) 
        TIMINGMATCH.SetTimingMatchState(TimingMatchState.FiveMinutes)
        local BuffWrite = buffrw.BuffWrite.new() 
        BuffWrite:int4(MatchConf["match_number"])
        for k, user in pairs(UserTb) do  
            --matchser.post.m_send_to_client(user.UserId,CMD.Main_match_module,CMD.Sub_ModuleToMatch_NotifyMatchStart5Min,BuffWrite.buff)
			TIMINGMATCH.SendFiveMinMail(user.UserId)
        end
        return
    end
       
end

--下发给客户端的预加入
function TIMINGMATCH.BroadCastLeft1MinutesPreJoin()
    local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime() 
    --if  (timeInterval <= SixtySeconds)  then
	if  (timeInterval <= 0)  then
        skynet.error("[timingmatch] TIMINGMATCH.BroadCastLeft1MinutesPreJoin  timeInterval <= SixtySeconds ")
        skynet.error("[timingmatch]  TIMINGMATCH.BroadCastLeft1MinutesPreJoin   timeNow,timeBase,start_time  timeInterval   ",timeNow,timeBase,MatchConf["start_time"],timeInterval) 
		TIMINGMATCH.SetTimingMatchState(TimingMatchState.OneMinutes)

        --local BuffWrite = buffrw.BuffWrite.new()
        --BuffWrite:int4(MatchConf["match_number"])
        --BuffWrite:int4(UserNum)
        --BuffWrite:int4(SixtySeconds) --人满比赛用不上该数据
        --BuffWrite:int1(MatchConf["icon_config"]["table_tu"]) 
            
        --for k, user in pairs(UserTb) do
        --   matchser.post.m_send_to_client(user.UserId,CMD.Main_match_module,CMD.Sub_MatchToModule_PreEnterRoomData,BuffWrite.buff)
        --   skynet.error("[timingmatch] PreJoinRoom userid ",user.UserId)
        --end 
		--TIMINGMATCH.SendMinutesMail()
		--skynet.timeout(2000,function() TIMINGMATCH.SendMinutesMail() end)
		
		skynet.fork(TIMINGMATCH.SendMinutesMail)
        MatchStage = MatchStage + 1 --比赛阶段
        return
    end
end

function TIMINGMATCH.SendMinutesMail()
	local nTimes = 0
    while true do
		skynet.error("[timingmatch]   TIMINGMATCH.SendMinutesMail nTimes ",nTimes)
		if TimingState ~= TimingMatchState.OneMinutes or nTimes > 5 then
			skynet.error("[timingmatch]   TIMINGMATCH.SendMinutesMail  TimingState ~= TimingMatchState.OneMinutes ")
			break
		end
		local BuffWrite = buffrw.BuffWrite.new()
		BuffWrite:int4(MatchConf["match_number"])
		BuffWrite:int4(UserNum)
		local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime() 
		skynet.error("[timingmatch]   TIMINGMATCH.SendMinutesMail  timeInterval = ",timeInterval)
		--if timeInterval > 0 then
		if (timeInterval > -60) and (timeInterval <= 0) then
			BuffWrite:int4( timeInterval+60 ) --人满比赛用不上该数据
			skynet.error("[timingmatch]   TIMINGMATCH.SendMinutesMail  timeInterval+60 = ",timeInterval+60)
		else
			BuffWrite:int4(0) --人满比赛用不上该数据
			skynet.error("[timingmatch]   TIMINGMATCH.SendMinutesMail  0 = ")
		end
		BuffWrite:int1(MatchConf["icon_config"]["table_tu"]) 
            
		for k, user in pairs(UserTb) do
			if user.State ~= UserState.RegisterOverWait then
				matchser.post.m_send_to_client(user.UserId,CMD.Main_match_module,CMD.Sub_MatchToModule_PreEnterRoomData,BuffWrite.buff)
				skynet.error("[timingmatch] SendMinutesMail userid ",user.UserId)
			end
		end
		nTimes = nTimes + 1
		skynet.sleep(1000)
	end
end

--客户端反馈预进入消息，没返回的则视为弃赛
function TIMINGMATCH.MinutesPreJoinBack(userid, msg)
    skynet.error("[timingmatch] MinutesPreJoinBack userid ",userid)
    TIMINGMATCH.SetUserState(userid, UserState.RegisterOverWait)
    matchser.post.m_send_to_center(userid, 1) ------------------------------&&&&&&&&&&&&&&&&&zdgzsdg
end

--弃赛通知邮件
function TIMINGMATCH.Abandon_match(userid)
	local totM = MatchConf["start_time"]/60
	local h = math.floor(totM/60)
	local m = math.floor(totM%60)
	if m < 10 then
		m = string.format("0%d", m)
	end
	local dateStr = os.date("%Y-%m-%d", os.time())
	skynet.error("[timingmatch] TIMINGMATCH.Abandon_match h m ",h,m)
	local title =  "弃赛提示"
    local body = "您报名的 "..dateStr.." "..h..":"..m.." 开始的".."“"..MatchConf["match_name"].."”".."因为没有及时到达，按弃赛处理,不返还报名费用。"
	skynet.error("[timingmatch] TIMINGMATCH.Abandon_match body ",body)
	local res1, res2 = db.call("call  pr_Addmsg("..userid..",201,\""..title.."\",\""..body.."\",@ReturnVal,@MsgId);", "select @ReturnVal,@MsgId;")

end

function TIMINGMATCH.FuncStartMatch()
    local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime() 
    --if timeInterval <= 0 and timeInterval >= -5 then
	if timeInterval <= -60 and timeInterval >= -65 then
        skynet.error("[timingmatch] TIMINGMATCH.FuncStartMatch  timeInterval <= 0 ")

        TIMINGMATCH.SetTimingMatchState(TimingMatchState.Matching)
        for i = #UserTb , 1 , -1 do 
            if UserTb[i].State ~= UserState.RegisterOverWait then
                skynet.error("[timingmatch] TIMINGMATCH.FuncStartMatch  State  UserId ",UserTb[i].State, UserTb[i].UserId)
                matchser.post.recv_user_addr(UserTb[i].UserId,MatchConf["match_number"],skynet.self(),0)
                TIMINGMATCH.AddUserLog(UserTb[i].UserId,DbIntState.MissMatch,0,UserTb[i].IsRboot,0)				
				TIMINGMATCH.Abandon_match(UserTb[i].UserId)
				table.remove(UserTb,i)
                UserNum = UserNum - 1
            end
        end
        TIMINGMATCH.StartMatch = os.date("%Y-%m-%d %H:%M:%S", os.time())
		
		local tempUserNum = UserNum
        if UserNum < MatchConf["min_man"] then   -- 是否大于人数下线
            tempUserNum = MatchConf["min_man"]
        elseif UserNum > MatchConf["min_man"] then   -- 是否大于人数下线
            if UserNum % TableUserNum == 0 then
                tempUserNum = UserNum
            else
                tempUserNum = UserNum + (TableUserNum - (UserNum % TableUserNum))
            end
        end
		skynet.error("[timingmatch]  TIMINGMATCH.FuncStartMatch   send MatchState CMD.MatchState_Matching  tempUserNum ",tempUserNum)
		matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_Matching,tempUserNum) --刷新状态
        TIMINGMATCH.ToGameCreatTable()
    end
end

function TIMINGMATCH.FuncEndMatch()
    skynet.error("[timingmatch] TIMINGMATCH.FuncEndMatch  ")
    TIMINGMATCH.SetTimingMatchState(TimingMatchState.Matchingend)
end

function TIMINGMATCH.ZeroResetMatch()
    local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime() 
    if (timeNow - timeBase) >= 0 and  (timeNow - timeBase) < 5 then
       --if (timeNow - 1508208600) >= 0 and  (timeNow - 1508208600) < 5 then 
            skynet.error("[timingmatch] TIMINGMATCH.ZeroResetMatch  (timeNow - timeBase) >= 0  (timeNow - timeBase) < 5 ")
            TIMINGMATCH.SetTimingMatchState(TimingMatchState.BeforeStartDate)   --- ?????
			skynet.error("[timingmatch] TIMINGMATCH.ZeroResetMatch  CMD.MatchState_ReadyMatch ")
            matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_ReadyMatch,0) --刷新状态
            MatchId = TIMINGMATCH.CreateUUID()
			TIMINGMATCH.GameAddr = nil
            TIMINGMATCH.TableId = ""
    end
end

function TIMINGMATCH.AfterEndDateMatch()
    local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime() 
    if (timeNow - MatchConf["end_date"] >= 0) and (timeNow - MatchConf["end_date"] <= 5) then
        skynet.error("[timingmatch] TIMINGMATCH.AfterEndDateMatch  timeNow >= end_date ")
        TIMINGMATCH.SetTimingMatchState(TimingMatchState.AfterEndDate)   
    end
end

function TIMINGMATCH.CheckMatchState()
    if  (TimingState == TimingMatchState.BeforeStartDate) then   --到了比赛有效期开始时
         TIMINGMATCH.Readymatch()
    elseif  (TimingState == TimingMatchState.Readymatch) then       --倒计时五分钟通知
         TIMINGMATCH.BroadCastLeft5MinutesToAll()
    elseif  (TimingState == TimingMatchState.FiveMinutes) then       --到时一分钟预进入
         TIMINGMATCH.BroadCastLeft1MinutesPreJoin()
    elseif  (TimingState == TimingMatchState.OneMinutes) then       --比赛
        TIMINGMATCH.FuncStartMatch()
    elseif  (TimingState == TimingMatchState.Matching) then       --比赛结束
        TIMINGMATCH.FuncEndMatch()   
    elseif  (TimingState ~= TimingMatchState.BeforeStartDate) then       --零点重置
        TIMINGMATCH.ZeroResetMatch()
    elseif  (TimingState ~= TimingMatchState.AfterEndDate) then       --过了有效期
        TIMINGMATCH.AfterEndDateMatch()
    end


end

-- function TIMINGMATCH.DuringStartDateCall()
    
-- end

--不断检测是否到开赛时间
function TIMINGMATCH.CheckOnTimeStart()

        
    while true do     --
        TIMINGMATCH.CheckMatchState()
        skynet.sleep(100)
    end
        
end

--获取距离开赛时间  返回 XX 秒
function TIMINGMATCH.GetTimesToStartTime()
    local timeNow = os.time()  --当前时间时间戳
    local MsgTime  = os.date("*t",timeNow)
    local baseYear  = MsgTime.year
    local baseMonth = MsgTime.month
    local baseDay   = MsgTime.day
    
    --凌晨零点的时间戳
    local timeBase = os.time({day=baseDay, month=baseMonth, year=baseYear, hour=0, minute=0, second=0})
    local timesToStartTime = MatchConf["start_time"] - (timeNow -timeBase)
    return timeNow,timeBase,timesToStartTime
end

-- function TIMINGMATCH.ResetFlage()

--     skynet.error("[timingmatch] ResetFlage ")
--     flag_zero = true
--     flag_5min = true
     
-- end

function TIMINGMATCH.ResetData()
    
    skynet.error("[timingmatch] TIMINGMATCH.ResetData ")
    for k, v in pairs(TableTb) do 
        TableTb[k] = nil
    end
   
    for i=1 ,#UserTb do 
		table.remove(UserTb,1) 
	end
    
    MatchStage = 0    
    
    UserNum = 0
end

function TIMINGMATCH.SendUserNumToAllUser()
    
    local BuffWrite = buffrw.BuffWrite.new()
    for index, user in pairs(UserTb) do 
        BuffWrite:clean()
        BuffWrite:int4(UserNum)
        matchser.post.m_send_to_client(user.UserId,CMD.Main_match_module,CMD.Sub_ModuleToMatch_UserNumChangeBack,BuffWrite.buff)
    end
end

--报名
function TIMINGMATCH.UserRegister(userid, msg) -- user = {UserId,NikeName} 

    local BuffRead = buffrw.BuffRead.new(msg)
    BuffRead:int4()
    --local userid = BuffRead:int4()
    local nikename = BuffRead:str(NameLen)
    local BuffWrite = buffrw.BuffWrite.new() 
    local Register = false 
    --BuffWrite:proto(CMD.Main_match_module,CMD.Sub_CenterToModule_PlayerBaoMingResult)
    BuffWrite:int4(MatchConf["match_number"])
    BuffWrite:int4(2)--定时赛
    skynet.error("[timingmatch] TIMINGMATCH.UserRegister UserNum  max_man  ",UserNum,MatchConf["max_man"])
    matchser.post.recv_user_addr(userid,MatchConf["match_number"],skynet.self(),0) 
    if MatchStage == CMD.MatchState_Pauseing  then 
        skynet.error("[timingmatch] UserRegister fail CMD.MatchState_Pauseing ",userid)
        BuffWrite:int4(2) --0 钻石不足 1成功 2其他原因失败          
    elseif UserNum >= MatchConf["max_man"]   then  --超过了上限
    --elseif UserNum >= MatchConf["min_man"]   then  --测试用
        BuffWrite:int4(3) --0 钻石不足 1成功 2其他原因失败  3：报名人数超过了上限
        skynet.error("[timingmatch] TIMINGMATCH.UserRegister 报名人数超过了上限   ",userid)      
    -- elseif TimingState >= TimingMatchState.FiveMinutes then  --剩5分钟则不予许再报名
    --     BuffWrite:int4(2) --0 钻石不足 1成功 2其他原因失败 
    --     skynet.error("[timingmatch] TIMINGMATCH.UserRegister TimingState >= TimingMatchState.FiveMinutes ") 
    else

        local Index = TIMINGMATCH.GetUserForUserTb(userid)
        if Index then 
            BuffWrite:int4(2)  
            skynet.error("[timingmatch] TIMINGMATCH.UserRegister 已经在表里，报名了   ",userid)     
        elseif TIMINGMATCH.DeductUserDiomand(userid) then --扣钻成功
            Register = true
            table.insert(UserTb,{UserId = userid, NikeName = nikename, Score = 0, CurJu = 0,IsRboot = 0, State = UserState.RegisterSucceed, TableId = 0})
            UserNum = UserNum +1
            BuffWrite:int4(1) --0 钻石不足 1成功 2其他原因失败 
            matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_ReadyMatch,UserNum)
            matchser.post.recv_user_addr(userid,MatchConf["match_number"],skynet.self(),1)
            --TIMINGMATCH.SendUserNumToAllUser()
            TIMINGMATCH.AddUserLog(userid,DbIntState.Registed,0,0,0)
			if TimingState == TimingMatchState.FiveMinutes then   --  五分钟内的下发通知
				skynet.timeout(500,function() TIMINGMATCH.SendFiveMinMail(userid) end)
			end
            skynet.error("[timingmatch] UserRegister succeed ",userid)
        else
            BuffWrite:int4(0) --0 钻石不足 1成功 2其他原因失败 
            skynet.error("[timingmatch] TIMINGMATCH.UserRegister 钻石不足   ",userid)       
        end
    end
    
    matchser.post.m_send_to_client(userid,CMD.Main_match_module,CMD.Sub_MatchToModule_PlayerBaoMingResult,BuffWrite.buff)
   
    -- if Register then --预进入房间
    --     BuffWrite:clean()
    --     BuffWrite:int4(MatchConf["match_number"])
    --     BuffWrite:int4(UserNum)
    --     BuffWrite:int4(0) --人满比赛用不上该数据
    --     BuffWrite:int1(MatchConf["icon_config"]["baominname"]) --人满比赛用不上该数据
    --     matchser.post.m_send_to_client(userid,CMD.Main_match_module,CMD.Sub_MatchToModule_PreEnterRoomData,BuffWrite.buff)
    -- end
end

function TIMINGMATCH.SendFiveMinMail(userid)
	local BuffWrite2 = buffrw.BuffWrite.new() 
	--BuffWrite2:int4(MatchConf["match_number"])
	BuffWrite2:int4(MatchConf["start_time"])
	BuffWrite2:str(MatchConf["match_name"],32)
	matchser.post.m_send_to_client(userid,CMD.Main_match_module,CMD.Sub_ModuleToMatch_NotifyMatchStart5Min,BuffWrite2.buff)
	skynet.error("[timingmatch] TIMINGMATCH.SendFiveMinMail   TimingMatchState.FiveMinutes send",MatchConf["start_time"],MatchConf["match_name"])
end

--比赛开始
function TIMINGMATCH.MatchStart()
    skynet.error("[timingmatch] MatchStart ")
    local BuffWrite = buffrw.BuffWrite.new() 
    BuffWrite:int4(skynet.self())
    local TablbNum = 0
    for tableid, tableobj in pairs(TableTb) do 
        TablbNum = TablbNum + 1
        BuffWrite:clean()
        BuffWrite:int4(tableid)
        for k, userid in pairs(tableobj.User) do 
            skynet.error("[timingmatch] MatchStart tableid userid: ",tableid, userid)
			TIMINGMATCH.SendAllNikeName(userid)
            matchser.post.m_send_to_client(userid,CMD.Main_match_module,CMD.Sub_MatchToModule_NotifyMatchStart,BuffWrite.buff)
            local index = TIMINGMATCH.GetUserForUserTb(userid)
            if UserTb[index] then 
                TIMINGMATCH.AddUserLog(userid,DbIntState.AttendMatch,0,UserTb[index].IsRboot,0)
            end
        end
    end
    --skynet.error("[timingmatch]  TIMINGMATCH.MatchStart   send MatchState CMD.MatchState_Matching  UserNum ",UserNum)
    --matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_Matching,UserNum) --刷新状态
    
    skynet.sleep(300)
    BuffWrite:clean()
    BuffWrite:proto(CMD.Main_match_module,CMD.Sub_NotifyMatchStart)
    BuffWrite:int4(skynet.self())
    BuffWrite:int4(TablbNum)
    for k, v in pairs(TableTb) do 
        BuffWrite:int4(k)
        matchser.post.m_send_to_game(k,BuffWrite.buff)
    end
    
    
end

--游戏服务器返回创建桌子结构
function CMD.recv_create_table(msg)

    local BuffRead = buffrw.BuffRead.new(msg)  
    BuffRead:proto()
    BuffRead:int4()
    local result = BuffRead:int4()
    TIMINGMATCH.CreatTable = true
    if result == 1 then 
        local TableCount =  BuffRead:int4()
        for i = 1, TableCount do
            local Tableid = BuffRead:int4()
			TIMINGMATCH.GameAddr = math.floor(Tableid / 10000)
            TIMINGMATCH.TableId = TIMINGMATCH.TableId..tostring(Tableid)..","
            skynet.error("[timingmatch] recv_create_table tableid: ",Tableid,TableCount)
            TableTb[Tableid] = {User = {}, CurJu = 0 }
            for j = 1, TableUserNum do 
                local userid = BuffRead:int4()
                skynet.error("[timingmatch] recv_create_table userid: ",userid)     
                table.insert(TableTb[Tableid].User, userid)
                local index = TIMINGMATCH.GetUserForUserTb(userid)
                if index then
                    UserTb[index].State = UserState.InMatchIng
                    UserTb[index].TableId = Tableid
                    UserTb[index].CurJu = 0
                   -- BuffRead:str(NameLen)
                   -- skynet.error("[timingmatch] recv_create_table nikename: ",UserTb[index].NikeName)                
                else 
                    --local name =  BuffRead:str(NameLen)                 
                   table.insert(UserTb,{UserId = userid, Score = 0, CurJu = 0,IsRboot = 1,State = UserState.InMatchIng, TableId = Tableid})
                   UserNum = UserNum + 1
                   skynet.error("[timingmatch] recv_create_table  robot  ",userid)
                end
            end
        end
		local RobotNum = BuffRead:int4()
        skynet.error("[timingmatch] recv_create_table RobotNum ",RobotNum)
        for i = 1, RobotNum do 
            local RobotId = BuffRead:int4()
            local RobotName = BuffRead:str(NameLen)
            skynet.error("[timingmatch] recv_create_table RobotId ",RobotId,RobotName)
            local index = TIMINGMATCH.GetUserForUserTb(RobotId)
            if index then                
                UserTb[index].NikeName = RobotName
            else
                skynet.error("[timingmatch] recv_create_table robot error")
            end
        end
        --通知游戏服务器和客户端开始比赛 
        TIMINGMATCH.MatchStart()
    else
        --处理逻辑未知
         for k, v in pairs(UserTb) do
        
            TIMINGMATCH.ReturnUserDiomand(v.UserId) --已报名的退钱 CMD.Sub_ModuleToMatch_NotifyMatchPause
            matchser.post.m_send_to_client(v.UserId, CMD.Main_match_module, CMD.Sub_ModuleToMatch_NotifyMatchPause,string.pack("I1",1))        
            skynet.error("[timingmatch] 游戏服务器创建桌子失败 userid: ",v.UserId,"赛赛id: ",MatchConf["match_name"],"游戏名称: ",MatchConf["game_type"] )
            matchser.post.recv_user_addr(v.UserId,MatchConf["match_number"],skynet.self(),0)
            matchser.post.m_send_to_center(v.UserId, 0)
        end
        matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_RunServer,0)
    end
  
    
end

function TIMINGMATCH.SendSortToAllUser()
    
    local BuffWrite = buffrw.BuffWrite.new()
    for index, user in pairs(UserTb) do 
        BuffWrite:clean()
        BuffWrite:int4(index)
        BuffWrite:int4(UserNum)
        matchser.post.m_send_to_client(user.UserId,CMD.Main_match_module,CMD.Sub_ModuleToMatch_RankChangeBack,BuffWrite.buff)
    end
end

function TIMINGMATCH.SortUserByScore()
    local tmp = 0    
    for i=1,#UserTb-1 do  
        for j=1,#UserTb-i do  
            if UserTb[j].Score < UserTb[j+1].Score then  
                tmp = UserTb[j] 
                UserTb[j] = UserTb[j+1]  
                UserTb[j+1] = tmp  
            end  
        end  
    end  
end

--检测该轮所有的桌子都结束打牌
function TIMINGMATCH.CheckAllTableOver()
    
    local AllOver = true
    for k, v in pairs(TableTb) do 
        if TableTb[k].CurJu ~= MatchConf["match_config"]["graden"][MatchStage]["jushu"] then 
            AllOver = false 
            skynet.error("[timingmatch] CheckAllTableOver  MatchStage ",MatchConf["match_config"]["graden"][MatchStage])
            skynet.error("[timingmatch] CheckAllTableOver has table not over one   ",TableTb[k].CurJu,MatchConf["match_config"]["graden"][MatchStage]["jushu"])  
            --发送等待其他桌子消息 Sub_MatchToModule_RoundOverData
            break
        end
    end
    --for k,v in pairs(UserTb) do
    --    skynet.error("[timingmatch] TIMINGMATCH.CheckAllTableOver  befor sort   ",v.NikeName,v.Score)
    --end
    --table.sort(UserTb,function(a,b) return (a.Score >= b.Score) end)
    TIMINGMATCH.SortUserByScore()
    --for k,v in pairs(UserTb) do
    --    skynet.error("[timingmatch] TIMINGMATCH.CheckAllTableOver  sort   ",v.NikeName,v.Score)
    --end
    TIMINGMATCH.SendSortToAllUser()
    local BuffWrite = buffrw.BuffWrite.new()
    if AllOver then  
		skynet.error("[timingmatch] TIMINGMATCH.CheckAllTableOver MatchStage = ",MatchStage)
        --local OutNum =MatchConf["match_config"]["graden"][MatchStage]["men"] --预计淘汰名次
        if MatchStage < MatchConf["match_config"]["grader_num"] then 
			local OutNum =MatchConf["match_config"]["graden"][MatchStage]["men"] --预计淘汰名次
            for i =1 , #UserTb do --排名后面的人淘汰
                BuffWrite:clean()
                BuffWrite:int4(i)
                 
                if i < OutNum + 1  then
                    UserTb[i].CurJu = 0 
                    matchser.post.m_send_to_client(UserTb[i].UserId,CMD.Main_match_module,Sub_MatchToModule_RoundOverJinJiData,BuffWrite.buff)   
                    skynet.error("[timingmatch] CheckAllTableOver in  ",UserTb[i].UserId,UserTb[i].Score)           
                else

					local nAwardId = TIMINGMATCH.CreatAwardMsg(UserTb[OutNum + 1].UserId,
																UserTb[OutNum + 1].NikeName,
																MatchConf["match_name"],
																i,
																0,
																0
																)
					
					
                    TIMINGMATCH.AddUserLog(UserTb[OutNum + 1].UserId,DbIntState.GetAward,0,UserTb[OutNum + 1].IsRboot,i)
					BuffWrite:int8(0)
                    BuffWrite:str(MatchConf["match_name"],32)
                    matchser.post.m_send_to_client(UserTb[OutNum + 1].UserId,CMD.Main_match_module,CMD.Sub_MatchToModule_BiSaiOverResult,BuffWrite.buff)
                    skynet.error("[timingmatch] CheckAllTableOver out ",UserTb[OutNum + 1].UserId,UserTb[OutNum + 1].Score)  
                    matchser.post.recv_user_addr(UserTb[OutNum + 1].UserId,MatchConf["match_number"],skynet.self(),0)
                    matchser.post.m_send_to_center(UserTb[OutNum + 1].UserId, 0)
                    table.remove(UserTb,OutNum + 1)
                    UserNum = UserNum -1
                    --matchser.post.recv_match_state(MatchConf["match_number"],3,UserNum) --比赛结束
                end            
            end
            MatchStage = MatchStage + 1 --比赛阶段
            for k, v in pairs(TableTb) do 
                TableTb[k] = nil
            end
            skynet.sleep(1000)
            TIMINGMATCH.ToGameCreatTable()
        elseif MatchStage >= MatchConf["match_config"]["grader_num"] then --最后一轮打完
            TIMINGMATCH.DealAward()
            --TODO 
            --**************************检测状态比赛是否失效**************************************--
            if skynet.time() < MatchConf["start_date"] or  skynet.time() > MatchConf["end_date"] then 
                matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_RunServer,UserNum) 
            end
            --todo 向数据库报告分数等，日志
            TIMINGMATCH.EndMatch = os.date("%Y-%m-%d %H:%M:%S", os.time())
            TIMINGMATCH.AddMatchLog()
            BuffWrite:clean()
            BuffWrite:proto(CMD.Main_match_module,CMD.Sub_NotifyMatchOver)
            BuffWrite:int4(skynet.self())
           -- matchser.post.create_table(MatchConf["game_type"],BuffWrite.buff)
            matchser.post.m_send_to_game(TIMINGMATCH.GameAddr*10000,BuffWrite.buff)
            --matchser.post.end_single_matchser(MatchConf["match_number"], skynet.self())
            skynet.error("[timingmatch]  TIMINGMATCH.CheckAllTableOver send CMD.MatchState_Match_end   MatchState ",CMD.MatchState_Match_end)
            matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_Match_end,0)
            TIMINGMATCH.ResetData()
        end
    else
        local WaitNum = 0
        for k, v in pairs(TableTb) do --统计未打完的桌子
            if v.CurJu ~= MatchConf["match_config"]["graden"][MatchStage]["jushu"]   then               
                WaitNum = WaitNum + 1
                skynet.error("[timingmatch] CheckAllTableOver the table not over tableid ",k)
            end
        end
        for k, v in pairs(TableTb) do 
            if v.CurJu == MatchConf["match_config"]["graden"][MatchStage]["jushu"]   then               
                for index, userid in pairs(v.User) do 
                    TIMINGMATCH.SetUserState(userid, UserState.MatchOverWait)
                    BuffWrite:clean()
                    BuffWrite:int4(WaitNum)   
                    matchser.post.m_send_to_client(userid,CMD.Main_match_module,CMD.Sub_MatchToModule_RoundOverData,BuffWrite.buff)
                    local i = TIMINGMATCH.GetUserForUserTb(userid)
                    skynet.error("[timingmatch] CheckAllTableOver has must wait ",userid,WaitNum)
                end
            end
        end
    end
        
end

-- 数据库生成消息
function TIMINGMATCH.CreatAwardMsg(userid, nikename, matchname, pos, prize_type, num)
    
    
    local title =  matchname.." 第"..pos.."名"
    local body = nil
    local msgtype = 201 
    local strname = string.sub(nikename,1,string.find(nikename,string.char(0))-1) 
    skynet.error("[timingmatch] CreatAwardMsg",userid, strname, matchname, pos, prize_type, num)
    if prize_type > 0 then
        local goods = nil
        if prize_type == 1 then 
            goods = "钻石奖励。"
            msgtype = 201  --领取 钻石 老友的消息类型，该类型不需要输入电话号码
        elseif prize_type == 2 then 
            goods = "老友豆奖励。"
            msgtype = 201
        elseif prize_type == 3 then 
            goods = "元话费奖励。"
            msgtype = 202   --领取 话费的消息类型，该类型需要输入电话号码
        end
      body = strname.."力战群雄，在“"..matchname.."”中获得第"..pos.."名，赢得"..num..goods
    else
        body = "真遗憾，"..strname.."在“"..matchname.."”中获得第"..pos.."名，差一点点就能拿到大奖了。"   
    end
    skynet.error("[timingmatch] CreatAwardMsg ",body)
    local sqlstr = "call pr_AddMatchAwardMsg("..userid..","..msgtype..",\""..title.."\",\""..body.."\","..prize_type..","..num..",@ReturnVal,@MsgId);"
    local res_sql = "select @ReturnVal,@MsgId;"
    local res1, res2 = db.call(sqlstr, res_sql)
    
    if res2[1]['@ReturnVal'] == 1 then 
        return res2[1]['@MsgId'] 
    else
        return 0
    end

end

--该场赛事结束后颁奖处理
function TIMINGMATCH.DealAward()
    skynet.error("[timingmatch]  TIMINGMATCH.DealAward")
    local BuffWrite = buffrw.BuffWrite.new()
    
    for i = 1, MatchConf["prize_config"]["prize_num"] do --有奖励的玩家处理             
        for Start = MatchConf["prize_config"]["prize"][i]["start_level"], MatchConf["prize_config"]["prize"][i]["end_level"] do 
            BuffWrite:clean() 
            BuffWrite:int4(Start)
            local prizeType = tonumber(MatchConf["prize_config"]["prize"][i]["prize_type"])
            local prizeNum = tonumber(MatchConf["prize_config"]["prize"][i]["num"])
            local nAwardId = TIMINGMATCH.CreatAwardMsg(UserTb[Start].UserId,
                                                    UserTb[Start].NikeName,
                                                    MatchConf["match_name"],
                                                    Start,
                                                    prizeType,
                                                    prizeNum
                                                    )
            BuffWrite:int8(nAwardId)
            BuffWrite:int4(MatchConf["prize_config"]["prize"][i]["prize_type"]) 
            BuffWrite:int4(MatchConf["prize_config"]["prize"][i]["num"])

            TIMINGMATCH.AddUserLog(UserTb[Start].UserId,DbIntState.GetAward,nAwardId,UserTb[Start].IsRboot,Start)
            matchser.post.m_send_to_client(UserTb[Start].UserId,CMD.Main_match_module,CMD.Sub_MatchToModule_BiSaiOverResult,BuffWrite.buff)
            matchser.post.m_send_to_center(UserTb[Start].UserId, 0)
            matchser.post.recv_user_addr(UserTb[Start].UserId,MatchConf["match_number"],skynet.self(),0)
        end
    end
    
    for i= MatchConf["win_man"]+1 , #UserTb do --没有奖励的玩家处理
        BuffWrite:clean()
        BuffWrite:int4(i)
        local nAwardId = TIMINGMATCH.CreatAwardMsg(UserTb[i].UserId,
                                                UserTb[i].NikeName,
                                                MatchConf["match_name"],
                                                i,
                                                0,
                                                0
                                                )
        BuffWrite:int8(0)
        BuffWrite:int4(0)
        BuffWrite:int4(0) 

        TIMINGMATCH.AddUserLog(UserTb[i].UserId,DbIntState.GetAward,0,UserTb[i].IsRboot,i)
        matchser.post.m_send_to_client(UserTb[i].UserId,CMD.Main_match_module,CMD.Sub_MatchToModule_BiSaiOverResult,BuffWrite.buff)
        matchser.post.m_send_to_center(UserTb[i].UserId, 0)
        matchser.post.recv_user_addr(UserTb[i].UserId,MatchConf["match_number"],skynet.self(),0)
    end
    
end

--获得比赛的详细信息
function  TIMINGMATCH.GetMatchInfo(UserId, msg)

    BuffRead = buffrw.BuffRead.new(msg)
    --local UserId = BuffRead:int4()
    local BuffWrite = buffrw.BuffWrite.new() 
    BuffWrite:int4(MatchConf["match_number"]) --赛事编号 
    BuffWrite:int4(MatchConf["game_type"])   --赛事玩法
    BuffWrite:int4(MatchConf["min_man"])  --最小人数

    BuffWrite:int1(MatchConf["icon_config"]["bao_min_sai_zi"])  --赛制类型（赛制图片地址）   
    BuffWrite:int1(MatchConf["icon_config"]["bao_min"])-- bao_min_sai_zi baomin_name  标题图片地址  
    BuffWrite:int1(MatchConf["icon_config"]["baomin_name"])  --奖励图片地址
    matchser.post.m_send_to_client(UserId, CMD.Main_match_module, CMD.Sub_MatchToModule_SingleBiSaiBack, BuffWrite.buff)
end

--收到一桌结算消息
function TIMINGMATCH.RevTableResult(msg)

    local BuffRead = buffrw.BuffRead.new(msg)  
    BuffRead:proto()
    BuffRead:int4()
    local TableId = BuffRead:int4()
    local UserNum = BuffRead:int4()
    local IsLu = BuffRead:int4()
    skynet.error("[timingmatch] RevTableResult tableid, usernum: ",TableId,UserNum)
	if TableTb[TableId] then
		TableTb[TableId].CurJu = TableTb[TableId].CurJu + 1
		skynet.error("[timingmatch] RevTableResult  TableTb[TableId].CurJu = ",TableTb[TableId].CurJu)
	end
    local UserId, Score, k
    for i = 1, UserNum do 
        UserId = BuffRead:int4()
        Score = BuffRead:int4()
        skynet.error("[timingmatch] RevTableResult 00000000 UserId,score ",UserId,Score)
        k = TIMINGMATCH.GetUserForUserTb(UserId)
        if k then 
           UserTb[k].Score =  UserTb[k].Score + Score
           UserTb[k].CurJu = UserTb[k].CurJu + 1
           --UserTb[k].State = UserState.MatchOverWait
           skynet.error("[timingmatch] RevTableResult userid,score curju: ",UserId,UserTb[k].Score,UserTb[k].CurJu)
        end
    end
    
    TIMINGMATCH.CheckAllTableOver()
    
end


--排行榜
function TIMINGMATCH.BiSaiRank(userid,msg)

    local BuffWrite = buffrw.BuffWrite.new() 
    BuffWrite:int4(#UserTb)     -- 排行榜人数
	skynet.error("[timingmatch]  TIMINGMATCH.BiSaiRank    #UserTb= ",#UserTb)
    for k, v in ipairs(UserTb) do 
		--skynet.error("[timingmatch]  TIMINGMATCH.BiSaiRank    +1 ")
        BuffWrite:int4(v.UserId)
        BuffWrite:int4(k)
        --BuffWrite:str(v.NikeName, NameLen)
        BuffWrite:int4(v.Score)
         if v.CurJu >= MatchConf["match_config"]["graden"][MatchStage]["jushu"] then 
            BuffWrite:int4(MatchConf["match_config"]["graden"][MatchStage]["jushu"])
        else
            BuffWrite:int4(v.CurJu)
        end
        BuffWrite:int4(MatchConf["match_config"]["graden"][MatchStage]["jushu"])
    end

    matchser.post.m_send_to_client(userid,CMD.Main_match_module,CMD.Sub_MatchToModule_BiSaiRankDataBack,BuffWrite.buff)
end

function TIMINGMATCH.SendAllNikeName(userid)
    
    local BuffWrite = buffrw.BuffWrite.new()
    BuffWrite:int4(#UserTb)
    for k, v in ipairs(UserTb) do 
        BuffWrite:int4(v.UserId) 
        local ok, nickname  = pcall(TIMINGMATCH.FormotGameNickName, v.NikeName,5)
        if ok then
            if string.len(nickname) > 24 then 
                skynet.error("[timingmatch] error 按照字数截取长度失败 ",string.len(nickname),nickname)
                nickname = string.sub(nickname,1,24)
            end
            BuffWrite:str(nickname, 24)
        else
            BuffWrite:str(" ", 24)
        end
    end  
    matchser.post.m_send_to_client(userid, CMD.Main_match_module, CMD.Sub_ModuleToMatch_SendAllUserNikeName, BuffWrite.buff)

end

function TIMINGMATCH.MatchOffBackData(userid, msg)
    
	TIMINGMATCH.SendAllNikeName(userid)
    local BuffWrite = buffrw.BuffWrite.new()
	skynet.error("[timingmatch] MatchOffBackData  userid =  ",userid)
    local index = TIMINGMATCH.GetUserForUserTb(userid)
    BuffWrite:int4(MatchStage)
    --skynet.error("[timingmatch] MatchOffBackData  state ",userid,type(userid),UserTb[index].State)
    if index then 
        BuffWrite:int4(UserTb[index].State)
		BuffWrite:int4(UserTb[index].Score)
		if MatchStage >0 and UserTb[index].CurJu >= MatchConf["match_config"]["graden"][MatchStage]["jushu"] then 
            BuffWrite:int4(MatchConf["match_config"]["graden"][MatchStage]["jushu"])
        else
            BuffWrite:int4(UserTb[index].CurJu)
        end
        if TimingState == TimingMatchState.FiveMinutes then   --  五分钟内的下发通知
            --local BuffWrite2 = buffrw.BuffWrite.new() 
            --BuffWrite2:int4(MatchConf["match_number"])
            --matchser.post.m_send_to_client(UserTb[index].UserId,CMD.Main_match_module,CMD.Sub_ModuleToMatch_NotifyMatchStart5Min,BuffWrite2.buff)
            TIMINGMATCH.SendFiveMinMail(UserTb[index].UserId)
			skynet.error("[timingmatch] MatchOffBackData   TimingMatchState.FiveMinutes send")
        end
    else
        BuffWrite:int4(0)
		BuffWrite:int4(0)
		BuffWrite:int4(0)
    end
	if MatchStage > 0 then
		BuffWrite:int4(MatchConf["match_config"]["graden"][MatchStage]["jushu"])
	else
		BuffWrite:int4(0)
	end
    BuffWrite:int4(MatchConf["match_number"])
    BuffWrite:int4(UserNum)
	local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime()
	if (TimingState == TimingMatchState.OneMinutes) and (timeInterval > 0) then   --  一分钟以内发剩余时间  xx 秒
		BuffWrite:int4(timeInterval)
	else
		BuffWrite:int4(0)
	end
     
    BuffWrite:int1(MatchConf["icon_config"]["table_tu"])   --牌桌底图 
    --人满比赛用不上该数据
    --当前轮数 MatchStage
    --当前用户状态 UserTb[k].State
    --比赛id MatchConf["match_number"]

    --
    matchser.post.m_send_to_client(userid, CMD.Main_match_module, CMD.Sub_ModuleToMatch_BiSaiOffBackMatch, BuffWrite.buff)
end

--取消报名
function  TIMINGMATCH.UserCancelRegister(UserId, msg)

    local BuffRead = buffrw.BuffRead.new(msg)
    BuffRead:int4()
   -- local UserId = BuffRead:int4()
    local BuffWrite = buffrw.BuffWrite.new()
    
    BuffWrite:int4(MatchConf["match_number"])
    BuffWrite:int4(UserId)
    skynet.error("[timingmatch] TIMINGMATCH.UserCancelRegister  UserNum TimingState   ",UserNum,TimingState)
    if (UserNum > 0) and (TimingState < TimingMatchState.FiveMinutes)  and TIMINGMATCH.ReturnUserDiomand(UserId) then --5分钟倒计时后不能退赛
        local index = TIMINGMATCH.GetUserForUserTb(UserId) 
        skynet.error("[timingmatch] TIMINGMATCH.UserCancelRegister  UserId index ",UserId,index)       
        if index then 
            table.remove(UserTb, index)
            UserNum = UserNum - 1         
            BuffWrite:int1(1)
            skynet.error("[timingmatch] UserCancelRegister succeed ",UserId)
            matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_ReadyMatch,UserNum) --比赛结束
            matchser.post.recv_user_addr(UserId,MatchConf["match_number"],skynet.self(),0)
            matchser.post.m_send_to_center(UserId, 0)
            --TIMINGMATCH.SendUserNumToAllUser()
            TIMINGMATCH.AddUserLog(UserId,DbIntState.Quit,0,0,0)
        else
            skynet.error("[timingmatch] UserCancelRegister fail not find user ",UserId)
            BuffWrite:int1(0)           
        end
    else
        skynet.error("[timingmatch] UserCancelRegister fail ",UserId)
        BuffWrite:int1(0)
    end

    matchser.post.m_send_to_client(UserId, CMD.Main_match_module, CMD.Sub_ModuleToMatch_CancelBaoMinBack, BuffWrite.buff)   
end

function TIMINGMATCH.GetRoomInfo(userid, msg)

    local BuffWrite = buffrw.BuffWrite.new()
    BuffWrite:int4(MatchStage)
    BuffWrite:int4(MatchConf["match_config"]["grader_num"]) --最大轮数
    BuffWrite:int4(TIMINGMATCH.GetUserForUserTb(userid))
    BuffWrite:int4(#UserTb)
    
    matchser.post.m_send_to_client(userid, CMD.Main_match_module, CMD.Sub_MatchToModule_BiSaiRoomInfo, BuffWrite.buff)
end

function TIMINGMATCH.BiSaiHelp(userid, msg)
    local BuffWrite = buffrw.BuffWrite.new()
    skynet.error("[timingmatch] TIMINGMATCH.BiSaiHelp MatchConf[icon_config][help] " ,MatchConf["icon_config"]["help"])
    BuffWrite:int4(MatchConf["icon_config"]["help"])   
    matchser.post.m_send_to_client(userid, CMD.Main_match_module, CMD.Sub_ModuleToMatch_BiSaiHelpInfoBack, BuffWrite.buff)
end

function TIMINGMATCH.MapMatchSer()

    matchser = cluster.snax("center", "matchser")
    if matchser then 
        skynet.error("[timingmatch] matchser server map succeed")
    else
        skynet.error("[timingmatch] matchser server map fail")
    end
 
    --matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_ReadyMatch,0) --刷新状态  -- 2 = MatchSta_ReadMatch     0
    
    --skynet.fork(TIMINGMATCH.CheckOnTimeStart) 
    --skynet.error("KKKKKKKKKKKKKKKKKKKK",MatchConf["match_config"]["graden"][1]["jushu"])
end


function CMD.recv_client(userid,scmd,msg)--mcmd,scmd,msg

    if CMD.Sub_ModuleToMatch_PlayerBaoMingReq == scmd then --报名
        TIMINGMATCH.UserRegister(userid, msg)
    elseif CMD.Sub_ModuleToMatch_GetSingleBiSaiReq == scmd then 
        TIMINGMATCH.GetMatchInfo(userid, msg) 
    elseif CMD.Sub_ModuleToMatch_CancelBaoMinReq == scmd then 
        TIMINGMATCH.UserCancelRegister(userid, msg)
    elseif CMD.Sub_ModuleToMatch_GetBiSaiRoomInfoReq == scmd then 
        TIMINGMATCH.GetRoomInfo(userid, msg)
    elseif CMD.Sub_ModuleToMatch_BiSaiRankDataReq == scmd then 
        TIMINGMATCH.BiSaiRank(userid,msg)
    elseif CMD.Sub_ModuleToMatch_BiSaiOffBack == scmd then
        TIMINGMATCH.MatchOffBackData(userid, msg)
    elseif CMD.Sub_ModuleToMatch_BiSaiPreJoinBack == scmd then
        TIMINGMATCH.MinutesPreJoinBack(userid, msg)
    elseif CMD.Sub_ModuleToMatch_GetBiSaiHelpInfo == scmd then
        TIMINGMATCH.BiSaiHelp(userid, msg)
    end   
end

function CMD.recv_game(scmd,msg)
    if CMD.Sub_RecvTableScore == scmd  then
       TIMINGMATCH.RevTableResult(msg)  
    end
end

function TIMINGMATCH.PublishMatch() --发布
    
    MatchStage = 0
    skynet.error("[timingmatch] PublishMatch")
    --if skynet.time() > MatchConf["start_date"] and  skynet.time() < MatchConf["end_date"] then 
       -- matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_ReadyMatch,UserNum) 
	    skynet.fork(TIMINGMATCH.CheckOnTimeStart) 
        MatchId = TIMINGMATCH.CreateUUID()
		TIMINGMATCH.GameAddr = nil
        TIMINGMATCH.TableId = ""
		local timeNow,timeBase,timeInterval = TIMINGMATCH.GetTimesToStartTime() 
		if skynet.time() > MatchConf["start_date"] and  skynet.time() < MatchConf["end_date"] then 
			if timeInterval < 0 then
				skynet.error("[timningmatch]   TIMINGMATCH.PublishMatch timeInterval < 0   CMD.MatchState_Match_end   end  end  end TIMINGMATCH.SetTimingMatchState(TimingMatchState.Matching)")
				TIMINGMATCH.SetTimingMatchState(TimingMatchState.Matching)
				matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_Match_end,0)
			end
		end
    --end
    
end

function TIMINGMATCH.PauseMatch() --暂停
  
    skynet.error("[timingmatch] PauseMatch")   
    if MatchStage < CMD.Match_ChuSai then  -- 比赛还未开始
        MatchStage = CMD.MatchState_Pauseing 
        for k, v in pairs(UserTb) do
            TIMINGMATCH.ReturnUserDiomand(v.UserId) --已报名的退钱 CMD.Sub_ModuleToMatch_NotifyMatchPause
            matchser.post.m_send_to_client(v.UserId, CMD.Main_match_module, CMD.Sub_ModuleToMatch_NotifyMatchPause,string.pack("I1",1))
            matchser.post.recv_user_addr(v.UserId,MatchConf["match_number"],skynet.self(),0)
            matchser.post.m_send_to_center(v.UserId, 0)
            skynet.error("[timingmatch] PauseMatch",v.UserId)
        end
    end
    matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_Pauseing,UserNum)
end

function TIMINGMATCH.CancelPublishMatch() --取消发布
    
    skynet.error("[timingmatch] CancelPublishMatch")   
    if MatchStage < CMD.Match_ChuSai then  -- 比赛还未开始
        MatchStage = CMD.MatchState_Pauseing
        for k, v in pairs(UserTb) do
            TIMINGMATCH.ReturnUserDiomand(v.UserId) --已报名的退钱 CMD.Sub_ModuleToMatch_NotifyMatchPause
            matchser.post.m_send_to_client(v.UserId, CMD.Main_match_module, CMD.Sub_ModuleToMatch_NotifyMatchPause,string.pack("I1",1))
            matchser.post.recv_user_addr(v.UserId,MatchConf["match_number"],skynet.self(),0)
            matchser.post.m_send_to_center(v.UserId, 0)
            skynet.error("[timingmatch] CancelPublishMatch",v.UserId) 
        end
    end
    matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_RunServer,UserNum) 
end

function TIMINGMATCH.OffLineMatch() -- 下线
   
    skynet.error("[timingmatch] OffLineMatch")
    for k, v in pairs(UserTb) do
        skynet.error("[timingmatch] OffLineMatch",v.UserId)    
    end
    matchser.post.recv_match_state(MatchConf["match_number"],CMD.MatchState_Error,UserNum) 
    -- if MatchStage < 1 then  -- 比赛还未开始
        -- MatchStage = CMD.MatchState_Pauseing 
        -- for k, v in pairs(UserTb) do
            -- TIMINGMATCH.ReturnUserDiomand(v.UserId) --已报名的退钱
        -- end
    -- end
end

function CMD.contrl(active_id)

    if active_id ==  CMD.MacthContrl_pause then 
    
        TIMINGMATCH.PauseMatch()
        
    elseif active_id == CMD.MacthContrl_publish then 
    
        TIMINGMATCH.PublishMatch() 
        
    elseif active_id == CMD.MacthContrl_not_publish then 
    
        TIMINGMATCH.CancelPublishMatch()
        
    elseif active_id == CMD.MacthContrl_not_online then
    
        TIMINGMATCH.OffLineMatch()
    end
end

function CMD.start(conf) 
    skynet.error("[timingmatch] timingmatch start ") 
	TIMINGMATCH.MapMatchSer()
    MatchConf = conf
    TableUserNum = MatchConf["room_config"]["player_num"]
    skynet.error("[timingmatch] start TableUserNum ",TableUserNum, type(TableUserNum))
    ----------------------     for  test -----------------------------
    local timeNow = os.time()  --当前时间
    local MsgTime  = os.date("*t",timeNow)
    local baseYear  = MsgTime.year
    local baseMonth = MsgTime.month
    local baseDay   = MsgTime.day
    local timeBase = os.time({day=baseDay, month=baseMonth, year=baseYear, hour=0, minute=0, second=0})

    --MatchConf["start_time"] = 240 + os.time() - timeBase
    ----------------------  end  for  test -----------------------------

    skynet.error("[timingmatch] match_config ".. MatchConf["match_config"]["graden"][1]["difen"])

    MatchStage = 0


    --启动查询是否到开赛时间进程
    

    -- MatchConf.start_time

    -- local nNowTime   = os.time()
    -- local Y = os.time(%Y)
    -- local Month = os.time(%m)
    -- local D = os.time(%d)
    -- local H = os.time(%H)
    -- local M = os.time(%M) 
    -- local nTimeStart = os.time({day=D, month=Month, year=Y, hour=MatchConf.H, minute=MatchConf.M, second=0})
    -- local delTime = nTimeStart - nNowTime

    --skynet.timeout(delTime - 300000, function() TIMINGMATCH.BroadCastLeftFiveMinutesToAll() end) --距离开始时间倒数五分钟通知

    --skynet.timeout(delTime - 60000, function() TIMINGMATCH.BroadCastLeftOneMinutesToAll() end) --距离开始时间倒数一分钟通知
    
    --skynet.timeout(delTime - 60000, function() TIMINGMATCH.PreJoinRoom() end) --开赛前一分钟下发预加入
    
    --skynet.timeout(delTime, function() TIMINGMATCH.CheckOnTimeStart() end) --距离开始时间倒数后开始比赛
end

function CMD.exit() 
    skynet.error("[timingmatch] ser exit ",skynet.self())
    skynet.exit()
end


skynet.start(function()
    skynet.dispatch("lua", function(session, source, cmd, subcmd, ...)
		local f = assert(CMD[cmd])
		skynet.ret(skynet.pack(f(subcmd, ...)))
	end)
    skynet.error("timingmatch start...")
    --skynet.timeout(20, function() TIMINGMATCH.MapMatchSer() end)
    math.randomseed(os.time())
end)